/*
muduo网络库给用户提供了两个主要的类
TcpServer：用于编写服务器程序
TcpClient：用于编写客户端程序

实际上就是epoll+线程池封装起来
好处：将网络I/O的代码和业务代码分开
网络的东西不用我们管
业务代码的暴露主要就两个：用户的连接和断开、用户的读写事件
*/
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <iostream>
#include <string>
#include <functional>
using namespace std;
using namespace muduo;
using namespace muduo::net;
using namespace placeholders;

/*
基于muduo网络库开发服务器程序
1.组合TcpServer对象
2.创建EventLoop事件循环对象的指针
3.明确TcpServer构造函数需要什么参数，输出ChatServer的构造函数
4.在当前服务器类的构造函数中，注册处理连接的回调函数和处理读写的回调函数
5.设置合适的服务端线程数量，muduo库会自动划分IO线程和worker线程

*/
class ChatServer
{
    public:
    //#3
    ChatServer(
        EventLoop* loop, //事件循环
        const InetAddress& listenAddr, //IP + Port
        const string& nameArg // 服务器名字
    ) : _server(loop, listenAddr, nameArg), _loop(loop) {
        //给服务器注册用户连接创建和断开的回调
        _server.setConnectionCallback(std::bind(&ChatServer::onConnection, this, _1));
        //给服务器注册用户读写事件回调
        _server.setMessageCallback(std::bind(&ChatServer::onMessage, this, _1, _2, _3));
        //设置服务器端的线程数量, 1个IO线程，3个worker线程
        _server.setThreadNum(4);

    }

    void start() {
        _server.start();
    }
    private:
        // 专门处理用户的连接创建和断开
        void onConnection(const TcpConnctionPtr& conn) {
           
            if (conn->connected()) {
                cout << conn->peerAddress().toIpPort() << " -> " << 
                    conn->localAddress().toIpPort() << "state: online" << endl;
            } else {
                cout << conn->peerAddress().toIpPort() << " -> " << 
                    conn->localAddress().toIpPort() << "state: offline" << endl;
                conn->shutdown();
                //_loop->quit();
            }

        }
        //处理用户读写事件
        void onMessage(const TcpConnctionPtr& conn, //连接
                        Buffer* buffer, //缓冲区
                        Timestamp time//接收数据的时间信息
                        ) {
                string buf = buffer->retrieveAllAsString();
                cout << "recv data: " << buf << " time: " << time.toString() << endl;
                /*
                处理接受的数据
                */
                conn->send(buf);//echo


        }
        TcpServer _server; //#1
        EventLoop *_loop; //#2看作epoll事件循环
};

int main() {
    EventLoop loop;//epoll
    InetAddress addr("127.0.0.1", 6000);
    ChatServer server(&loop, addr, "ChatServer");
    
    server.start();//启动服务 
    loop.loop; //epoll_wait()以阻塞方式等待用户连接或读写事件

    return 0;
}